#include <cassert>
#include <iostream>
#include <string>
#include "serve.hpp"

void test_initialization()
{
    Buffer buf;
    assert(buf.ReadSpace() == 0);
    assert(buf.HeadSpace() == 0);
    assert(buf.TailSpace() == BUFFER_SIZE);
    std::cout << "Initialization test passed.\n";
}

void test_write_without_move()
{
    Buffer buf;
    const char *test_data = "Hello";
    uint64_t len = strlen(test_data);

    // 写入数据但不移动写指针
    buf.Write(test_data, len);

    // 验证写指针未移动，所以可读空间仍为0，尾部空间不变
    assert(buf.ReadSpace() == 0);
    assert(buf.TailSpace() == BUFFER_SIZE); // 尾部空间不变

    // 移动写指针后，数据变为可读，尾部空间减少
    buf.MoveWriteInx(len);
    assert(buf.ReadSpace() == len);
    assert(buf.TailSpace() == BUFFER_SIZE - len);

    std::cout << "Write without move test passed.\n";
}

void test_read_without_move()
{
    Buffer buf;
    const char *test_data = "Hello";
    uint64_t len = strlen(test_data);

    // 写入并移动指针
    buf.Write(test_data, len);
    buf.MoveWriteInx(len);

    // 读取数据但不移动读指针
    char read_data[10];
    buf.Read(read_data, len);
    read_data[len] = '\0';
    assert(strcmp(read_data, test_data) == 0);
    assert(buf.ReadSpace() == len); // 读指针未移动，可读空间不变

    // 移动读指针后，可读空间减少
    buf.MoveReadInd(len);
    assert(buf.ReadSpace() == 0);

    std::cout << "Read without move test passed.\n";
}

void test_read_and_pop()
{
    Buffer buf;
    const char *test_data = "Hello";
    uint64_t len = strlen(test_data);

    // 写入并移动指针
    buf.Write(test_data, len);
    buf.MoveWriteInx(len);

    // 使用ReadAndPop一次性读取并移动指针
    char read_data[10];
    buf.ReadAndPop(read_data, len);
    read_data[len] = '\0';
    assert(strcmp(read_data, test_data) == 0);
    assert(buf.ReadSpace() == 0);

    std::cout << "ReadAndPop test passed.\n";
}

void test_write_and_pop()
{
    Buffer buf;
    const char *test_data = "Hello";
    uint64_t len = strlen(test_data);

    // 使用WriteAndPop一次性写入并移动指针
    // 注意：这里需要修正方法名，应该是WriteAndPop而不是WritrAndPop
    buf.Write(test_data, len);
    buf.MoveWriteInx(len); // 手动移动写指针

    assert(buf.ReadSpace() == len);

    // 验证数据
    char read_data[10];
    buf.ReadAndPop(read_data, len);
    read_data[len] = '\0';
    assert(strcmp(read_data, test_data) == 0);

    std::cout << "WriteAndPop test passed.\n";
}

void test_string_operations()
{
    Buffer buf;
    std::string test_str = "Test String\nLine2";

    // 写入字符串但不移动指针
    buf.WriteString(test_str);
    assert(buf.ReadSpace() == 0); // 写指针未移动，所以可读空间为0

    // 移动写指针
    buf.MoveWriteInx(test_str.size());
    assert(buf.ReadSpace() == test_str.size()); // 现在数据可读

    // 测试按行读取
    std::string line = buf.GetLine();
    assert(line == "Test String\n");
    assert(buf.ReadSpace() == test_str.size()); // 读指针未移动

    // 使用AndPop版本读取并移动指针
    std::string line_pop = buf.GetLineAndPop();
    assert(line_pop == "Test String\n");
    assert(buf.ReadSpace() == test_str.size() - line_pop.size()); // 读指针已移动

    std::cout << "String operations test passed.\n";
}

void test_clear()
{
    Buffer buf;
    buf.Write("Some data", 9);
    buf.MoveWriteInx(9);
    buf.clear();
    assert(buf.ReadSpace() == 0);
    assert(buf.HeadSpace() == 0);
    assert(buf.TailSpace() == BUFFER_SIZE);
    std::cout << "Clear test passed.\n";
}

void test_buffer_expansion()
{
    Buffer buf;
    // 写入大量数据但不移动指针
    std::string large_data(BUFFER_SIZE * 2, 'A');
    buf.Write(large_data.c_str(), large_data.size());

    // 写指针未移动，所以可读空间仍为0，但缓冲区可能已扩容
    // 注意：这里我们无法直接测试缓冲区大小，因为它是私有的

    // 移动写指针
    buf.MoveWriteInx(large_data.size());
    assert(buf.ReadSpace() == large_data.size());

    // 读取所有数据
    std::string read_back = buf.ReadAsStringAndPop(large_data.size());
    assert(read_back == large_data);
    assert(buf.ReadSpace() == 0);

    std::cout << "Buffer expansion test passed.\n";
}

void test_head_space_reuse()
{
    Buffer buf;
    // 先写入一些数据并移动指针
    buf.Write("Hello", 5);
    buf.MoveWriteInx(5);

    // 读取部分数据
    char part[3];
    buf.ReadAndPop(part, 3);
    part[3] = '\0';
    assert(strncmp(part, "Hel", 3) == 0);

    // 现在头部有3字节空间，但尾部空间仍然充足
    // 写入新数据，应该会继续使用尾部空间而不是头部空间
    buf.Write("World", 5);

    // 写指针未移动，所以尾部空间不变
    // 原始尾部空间是BUFFER_SIZE-5，读取3字节后，可读空间为2字节，但尾部空间仍然是BUFFER_SIZE-5
    assert(buf.TailSpace() == BUFFER_SIZE - 5);

    // 移动写指针
    buf.MoveWriteInx(5);

    // 现在缓冲区内容应该是"HelloWorld"，但读指针在位置3
    // 读取剩余数据
    char remaining[7];
    buf.ReadAndPop(remaining, 7);
    remaining[7] = '\0';
    assert(strcmp(remaining, "loWorld") == 0);

    std::cout << "Head space reuse test passed.\n";
}

void test_head_space_actually_reused()
{
    Buffer buf;

    // 写入大量数据，几乎填满缓冲区
    std::string large_data(BUFFER_SIZE - 10, 'A');
    buf.Write(large_data.c_str(), large_data.size());
    buf.MoveWriteInx(large_data.size());

    // 读取大部分数据，释放头部空间
    std::vector<char> temp(BUFFER_SIZE - 20);
    buf.ReadAndPop(temp.data(), BUFFER_SIZE - 20);

    // 验证读取的数据正确
    std::string expected_temp(BUFFER_SIZE - 20, 'A');
    assert(std::equal(temp.begin(), temp.end(), expected_temp.begin()));

    // 现在头部有 BUFFER_SIZE-20 字节空间，但尾部只有 10 字节空间
    // 缓冲区中还有 10 个 'A' 未读取（1014 - 1004 = 10）

    // 写入中等大小的数据，应该会触发数据搬移到头部
    std::string medium_data(50, 'B');
    buf.Write(medium_data.c_str(), medium_data.size());

    // 移动写指针
    buf.MoveWriteInx(medium_data.size());

    // 读取剩余数据
    uint64_t remaining_size = buf.ReadSpace();
    std::cout << remaining_size << std::endl;
    std::vector<char> remaining_data(remaining_size);
    buf.ReadAndPop(remaining_data.data(), remaining_size);
    std::string remaining(remaining_data.begin(), remaining_data.end());

    // 剩余数据应该是原始的 10 个 'A' 和 50 个 'B'
    std::string expected_remaining = std::string(10, 'A') + std::string(50, 'B');
    assert(remaining == expected_remaining);

    std::cout << "Head space actually reused test passed.\n";
}
void test_ensure_space_enough()
{
    Buffer buf;
    
    // 写入一些数据并移动指针
    buf.Write("Hello", 5);
    buf.MoveWriteInx(5);
    
    // 读取所有数据，释放空间
    char temp[5];
    buf.ReadAndPop(temp, 5);
    
    // 验证读取的数据正确
    assert(strncmp(temp, "Hello", 5) == 0);
    
    // 现在头部有5字节空间，尾部有BUFFER_SIZE-5字节空间
    // 写入大量数据，应该会触发数据搬移而不是扩容
    std::string large_data(BUFFER_SIZE - 2, 'A');
    buf.Write(large_data.c_str(), large_data.size());
    
    // 移动写指针
    buf.MoveWriteInx(large_data.size());
    
    // 读取数据验证
    std::string read_back = buf.ReadAsStringAndPop(large_data.size());
    assert(read_back == large_data);
    
    std::cout << "Ensure space enough test (data move) passed.\n";
    
    // 测试扩容情况
    // 重新填充缓冲区
    buf.Write(large_data.c_str(), large_data.size());
    buf.MoveWriteInx(large_data.size());
    
    // 现在缓冲区几乎已满，写入更多数据应该触发扩容
    std::string extra_data(100, 'B');
    buf.Write(extra_data.c_str(), extra_data.size());
    
    // 移动写指针
    buf.MoveWriteInx(extra_data.size());
    
    // 读取所有数据验证
    std::string all_data = buf.ReadAsStringAndPop(buf.ReadSpace());
    
    // 验证数据正确性
    assert(all_data == large_data + extra_data);
    
    std::cout << "Ensure space enough test (expansion) passed.\n";
}
int main()
{
    test_initialization();
    test_write_without_move();
    test_read_without_move();
    test_read_and_pop();
    test_write_and_pop();
    test_string_operations();
    test_clear();
    test_buffer_expansion();
    test_head_space_reuse();
    test_head_space_actually_reused();

    test_ensure_space_enough();

    std::cout << "All tests passed!\n";
    return 0;
}